package com.hzzftech.watchdog.busi.controller;

import com.hzzftech.watchdog.busi.constants.BusiConstant;
import com.hzzftech.watchdog.busi.core.file.repository.FileRepositoryManager;
import com.hzzftech.watchdog.busi.core.file.repository.KtFileRepositoryFileParser;
import com.hzzftech.watchdog.busi.domain.*;
import com.hzzftech.watchdog.busi.exception.FileTypeException;
import com.hzzftech.watchdog.busi.service.IKtDispatcherService;
import com.hzzftech.watchdog.busi.service.IKtFileRepositoryMsgService;
import com.hzzftech.watchdog.busi.service.IKtFileRepositoryService;
import com.hzzftech.watchdog.busi.service.IKtFileVersionService;
import com.hzzftech.watchdog.busi.utils.FileUtils;
import com.hzzftech.watchdog.busi.utils.ZipUtil;
import com.hzzftech.watchdog.common.annotation.Log;
import com.hzzftech.watchdog.common.config.KtWatchdogConfig;
import com.hzzftech.watchdog.common.constant.Constants;
import com.hzzftech.watchdog.common.core.controller.BaseController;
import com.hzzftech.watchdog.common.core.domain.AjaxResult;
import com.hzzftech.watchdog.common.core.domain.Ztree;
import com.hzzftech.watchdog.common.core.page.TableDataInfo;
import com.hzzftech.watchdog.common.enums.BusinessType;
import com.hzzftech.watchdog.common.utils.StringUtils;
import com.hzzftech.watchdog.common.utils.file.FileUploadUtils;
import com.hzzftech.watchdog.common.utils.poi.ExcelUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

/**
 * 文件资源库-文件信息Controller
 * 
 * @author kt-watchdog
 * @date 2021-12-09
 */
@Controller
@RequestMapping("/busi/file/msg")
public class KtFileRepositoryMsgController extends BaseController
{
    private String prefix = "busi/file/msg";

    @Autowired
    private IKtFileRepositoryMsgService ktFileRepositoryMsgService;

    @Autowired
    private IKtFileRepositoryService iKtFileRepositoryService;

    @Autowired
    private IKtFileVersionService versionService;

    @Value("${kt-watchdog.profile}")
    private String PROFIX_STR;

    @Value("${kt-watchdog.file_repository_location}")
    private String FILE_REPOSITORY_LOCATION;

    @Autowired
    private IKtDispatcherService ktDispatcherService;

    public static Logger logger = LoggerFactory.getLogger(KtFileRepositoryMsgController.class);

    @RequiresPermissions("busi:msg:view")
    @GetMapping("/{repoId}")
    public String msg(@PathVariable("repoId") Long repoId, ModelMap mmap, @RequestParam("selectedIds") String selectedIds)
    {
        mmap.addAttribute("repoId", repoId);
        mmap.addAttribute("repoName", iKtFileRepositoryService.selectKtFileRepositoryById(repoId).getName());
        mmap.addAttribute("selectedIds", selectedIds);
        return "busi/dispatcher/file_repo_file";
    }

    /**
     * 查询文件资源库-文件信息列表
     */
    @RequiresPermissions("busi:msg:list")
    @PostMapping("/list/{repoId}")
    @ResponseBody
    public  List<KtFileRepositoryMsg> list(@PathVariable("repoId") Long repoId, KtFileRepositoryMsg ktFileRepositoryMsg)
    {
        ktFileRepositoryMsg.setfRepoId(repoId);
        List<KtFileRepositoryMsg> list = ktFileRepositoryMsgService.selectKtFileRepositoryMsgList(ktFileRepositoryMsg);
        return list;
    }

    /**
     * 查询文件资源库-文件信息列表
     */
    @RequiresPermissions("busi:msg:list")
    @PostMapping("/list2/{repoId}")
    @ResponseBody
    public TableDataInfo list2(@PathVariable("repoId") Long repoId, KtFileRepositoryMsg ktFileRepositoryMsg)
    {
        startPage();
        ktFileRepositoryMsg.setfRepoId(repoId);
        ktFileRepositoryMsg.setFileType(BusiConstant.REPOSITORY_TYPE_FILE);
        List<KtFileRepositoryMsg> list = ktFileRepositoryMsgService.selectKtFileRepositoryMsgList(ktFileRepositoryMsg);
        return getDataTable(list);
    }

    /**
     * 新增文件资源库-文件信息
     */
    @GetMapping("/add")
    public String add()
    {
        return prefix + "/add";
    }

    /**
     * 新增按钮
     * @param parentId
     * @param repoId
     * @param mmap
     * @return
     */
    @GetMapping("/add/{repoId}/{parentId}")
    public String add(@PathVariable("repoId") Long repoId, @PathVariable("parentId") Long parentId, ModelMap mmap)
    {
        KtFileRepositoryMsg file = ktFileRepositoryMsgService.selectRepoById(repoId, parentId);
        mmap.put("repo", file);
        return prefix + "/add";
    }


    @GetMapping("selectRepoFileTree/{repoId}/{id}")
    public String selectRepoFileTree(@PathVariable("repoId") Long repoId,@PathVariable("id") Long id, ModelMap mmap) {
        KtFileRepositoryMsg f = ktFileRepositoryMsgService.selectRepositoryFileByRepoIdAndFid(repoId, id);
        mmap.put("repo",f);
        return prefix + "/tree";
    }


    @ResponseBody
    @GetMapping("fileTreeData/{repoId}")
    public  List<Ztree> zTree(@PathVariable("repoId") Long repoId) {
        // 组装文件树结构
        List<Ztree> ztrees = new ArrayList<Ztree>();
        List<KtFileRepositoryMsg> files = ktFileRepositoryMsgService.selectKtRepositoryByRepoId(repoId);
        boolean isCheck = StringUtils.isNotNull(files);
        for (KtFileRepositoryMsg file : files)
        {
            Ztree ztree = new Ztree();
            ztree.setId(file.getId());
            ztree.setpId(file.getParentId());
            ztree.setName(file.getFileName());
            if (file.getParentId().equals(0L)) {
                ztree.setTitle(file.getRepositoryName());
            }
            if (isCheck)
            {
                ztree.setChecked(true);
            }
            ztrees.add(ztree);
        }
        return ztrees;
    }

    /**
     * 新增保存文件资源库-文件信息
     */
    @RequiresPermissions("busi:msg:add")
    @Log(title = "文件资源库-文件信息", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(KtFileRepositoryMsg ktFileRepositoryMsg)
    {
        return toAjax(ktFileRepositoryMsgService.insertKtFileRepositoryMsg(ktFileRepositoryMsg));
    }

    /**
     * 修改文件资源库-文件信息
     */
    @RequiresPermissions("busi:msg:edit")
    @GetMapping("/edit/{id}")
    public String edit(@PathVariable("id") Long id, ModelMap mmap)
    {
        KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
        mmap.put("ktFileRepositoryMsg", ktFileRepositoryMsg);
        return prefix + "/edit";
    }

    /**
     * 修改保存文件资源库-文件信息
     */
    @RequiresPermissions("busi:msg:edit")
    @Log(title = "文件资源库-文件信息", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(KtFileRepositoryMsg ktFileRepositoryMsg)
    {
        return toAjax(ktFileRepositoryMsgService.updateKtFileRepositoryMsg(ktFileRepositoryMsg));
    }

    /**
     * 删除文件资源库-文件信息
     */
    @RequiresPermissions("busi:msg:remove")
    @Log(title = "文件资源库-文件信息", businessType = BusinessType.DELETE)
    @GetMapping( "/remove/{id}")
    @ResponseBody
    public AjaxResult remove(@PathVariable("id") Long id)
    {
        KtFileRepositoryMsg msg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
        if (msg == null) {
            return AjaxResult.error("没有查询到要删除的文件信息");
        }

        KtDispatcher ktDispatcher = new KtDispatcher();
        ktDispatcher.setDpRepoType(BusiConstant.REPOSITORY_TYPE_FILE);
        ktDispatcher.setDpId(id);
        List<KtDispatcher> list = ktDispatcherService.selectKtDispatcherList(ktDispatcher);
        if (list.size() > 0) {
            return AjaxResult.error("文件已被调度引用，如果要删除此文件，请先删除引用此文件的调度");
        }
        return toAjax(ktFileRepositoryMsgService.deleteKtFileRepositoryMsgById(id));
    }

    @GetMapping("/treeData/{repoId}")
    @ResponseBody
    public List<Ztree> treeData(@PathVariable("repoId") Long repoId) throws FileNotFoundException, FileTypeException {
        KtFileRepository ktFileRepository = iKtFileRepositoryService.selectKtFileRepositoryById(repoId);
        // 解析文件资源仓库
        FileRepositoryManager manager = new FileRepositoryManager(FILE_REPOSITORY_LOCATION, ktFileRepository.getDirectory(),
                new KtFileRepositoryFileParser(ktFileRepositoryMsgService,versionService, repoId, FILE_REPOSITORY_LOCATION));
        manager.parse();
        List<Ztree> ztrees = ktFileRepositoryMsgService.selectFileTree(repoId);
        return ztrees;
    }

    @ResponseBody
    @PostMapping("/changeStatus")
    public AjaxResult changeStatus(KtFileRepositoryMsg msg) {
        if (Objects.isNull(msg)||Objects.isNull(msg.getfRepoId()) || Objects.isNull(msg.getId()) || StringUtils.isEmpty(msg.getStatus())) {
            return AjaxResult.error("更新文件状态失败");
        }
        String status = msg.getStatus();
        int count = 0;
        // 文件资源仓库，切换版本
        if (status.equals(BusiConstant.STATUS_YES)) {
            KtFileRepositoryMsg msgDB = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(msg.getId());
            List<KtFileRepositoryMsg> parents = ktFileRepositoryMsgService.selectListByRepoIds(msgDB.getAncestors().split(","));
            for (KtFileRepositoryMsg g : parents){
                if (g.getStatus().equals(BusiConstant.STATUS_NO)) {
                    return AjaxResult.error("父目录“"+g.getFileName()+"“为禁用状态，不允许启用");
                }
            }
            List<KtFileRepositoryMsg> list = ktFileRepositoryMsgService.selectKtFileRepositoryMsgWithChild(msg.getfRepoId(),msg.getId() );
            for (KtFileRepositoryMsg m:
                    list) {
                m.setStatus(status);
                ktFileRepositoryMsgService.updateKtFileRepositoryMsg(m);
                count++;
            }
        } else {
            List<KtFileRepositoryMsg> list = ktFileRepositoryMsgService.selectKtFileRepositoryMsgWithChild(msg.getfRepoId(),msg.getId() );
            for (KtFileRepositoryMsg m:
                    list) {
                m.setStatus(status);
                ktFileRepositoryMsgService.updateKtFileRepositoryMsg(m);
                count++;
            }
        }
        return toAjax(count);
    }

    @GetMapping("/addFileOrDirectory/{id}")
    public String addFileOrDirectory(@PathVariable("id") Long id, ModelMap mmap) {
        KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
        mmap.addAttribute("fileMsg",ktFileRepositoryMsg );
        return prefix + "/add";
    }

    @Log(title = "导入文件或文件夹", businessType = BusinessType.INSERT)
    @PostMapping("/addFileOrZipDirectory")
    @ResponseBody
    public AjaxResult addFileOrZipDirectory(@RequestParam("fileOrD") MultipartFile file,@RequestParam("id") Long id, @RequestParam("parentId") Long parentId,  @RequestParam("fRepoId") Long fRepoId)
    {
        String fileName = null;
        try
        {
            if (!file.isEmpty())
            {
                fileName = FileUploadUtils.upload(KtWatchdogConfig.getUploadPath(), file);
                fileName = fileName.substring(Constants.RESOURCE_PREFIX.length());
                KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
                if (Objects.isNull(ktFileRepositoryMsg) || ktFileRepositoryMsg.getFileType().equals(BusiConstant.FILE_TYPE_F)) {
                    return AjaxResult.error("没有找到文件夹或不是文件夹");
                }

                KtFileRepositoryFileParser paraser = new KtFileRepositoryFileParser(
                        ktFileRepositoryMsgService, versionService, fRepoId,FILE_REPOSITORY_LOCATION
                );

                if (FileUtils.getSuffixName(fileName).equals("zip")) {
                    // 导入zip文件
                    ZipUtil.unZipFiles(PROFIX_STR+fileName, FILE_REPOSITORY_LOCATION+paraser.getFilePath(ktFileRepositoryMsg)+File.separator);
                } else {
                    // 导入单个文件
                    FileUtils.copyFile(PROFIX_STR+fileName, FILE_REPOSITORY_LOCATION+paraser.getFilePath(ktFileRepositoryMsg)+File.separator+file.getOriginalFilename());
                }

                KtFileRepository ktFileRepository = iKtFileRepositoryService.selectKtFileRepositoryById(fRepoId);
                // 解析文件资源仓库
                FileRepositoryManager manager = new FileRepositoryManager(FILE_REPOSITORY_LOCATION, ktFileRepository.getDirectory(),
                        paraser);
                manager.parse();

            }
        }
        catch (Exception e)
        {
            logger.error("文件上传失败！", e);
            return error(e.getMessage());
        }

        return success();
    }

    // 添加文件夹
    @GetMapping("/addDirectory/{id}")
    public String addDirectory(@PathVariable("id") Long id, ModelMap mmap) {
        KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
        mmap.addAttribute("fileMsg",ktFileRepositoryMsg );
        return prefix + "/addDirectory";
    }

    // 添加文件夹保存
    @Log(title = "新增文件夹", businessType = BusinessType.UPDATE)
    @PostMapping("/addDirectory")
    @ResponseBody
    public AjaxResult addFileOrZipDirectory( KtFileRepositoryMsg msg)
    {
        if (msg.getId() == null || msg.getfRepoId() == null||msg.getFileName() == null) {
            return error();
        }
        KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(msg.getId());
        KtFileRepositoryFileParser paraser = new KtFileRepositoryFileParser(
                ktFileRepositoryMsgService, versionService, msg.getfRepoId(),FILE_REPOSITORY_LOCATION
        );

        // 获取父文件夹
        String parentPath = FILE_REPOSITORY_LOCATION + paraser.getFilePath(ktFileRepositoryMsg);
        File f = new File(parentPath+ File.separator+msg.getFileName());
        f.mkdir();
        // 文件资源仓库解析
        FileRepositoryManager manager = new FileRepositoryManager(
                FILE_REPOSITORY_LOCATION,
                iKtFileRepositoryService.selectKtFileRepositoryById(msg.getfRepoId()).getDirectory(),
                paraser
        );
        manager.parse();

        return AjaxResult.success();
    }

    @GetMapping("/addVersion/{id}")
    public String addVersion(@PathVariable("id") Long id, ModelMap mmap) {
        KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
        mmap.addAttribute("fileMsg",ktFileRepositoryMsg );
        return prefix + "/addVersion";
    }

    @Log(title = "新增文件或文件夹", businessType = BusinessType.INSERT)
    @PostMapping("/addVersion")
    @ResponseBody
    public AjaxResult addVersion(@RequestParam("file") MultipartFile file,@RequestParam("id") Long id, @RequestParam("parentId") Long parentId,  @RequestParam("fRepoId") Long fRepoId)
    {
        String fileName = null;
        try
        {
            if (!file.isEmpty())
            {
                KtFileRepositoryMsg ktFileRepositoryMsg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(id);
                if (Objects.isNull(ktFileRepositoryMsg) || !ktFileRepositoryMsg.getFileType().equals(BusiConstant.FILE_TYPE_F)) {
                    return AjaxResult.error("资源库中未找到文件信息"+file.getOriginalFilename());
                }

                if (!ktFileRepositoryMsg.getFileName().equals(file.getOriginalFilename())) {
                    return AjaxResult.error("文件名称不一致，应上传文件名为【"+ktFileRepositoryMsg.getFileName()+"】的文件");
                }

                fileName = FileUploadUtils.upload(KtWatchdogConfig.getUploadPath(), file).substring(Constants.RESOURCE_PREFIX.length());

                KtFileRepositoryFileParser paraser = new KtFileRepositoryFileParser(
                        ktFileRepositoryMsgService, versionService, fRepoId,FILE_REPOSITORY_LOCATION
                );
                KtFileRepository repository = iKtFileRepositoryService.selectKtFileRepositoryById(fRepoId);
                // 文件版本
                String version = UUID.randomUUID().toString();
                // 当前有效版本文件路径
                String workFilePath = FILE_REPOSITORY_LOCATION+paraser.getFilePath(ktFileRepositoryMsg);
                // 待切换版本
                String versionFilePath =FILE_REPOSITORY_LOCATION+File.separator+"version_"+repository.getDirectory()+File.separator+version;
                FileUtils.deleteFile(workFilePath);
                FileUtils.copyFile(PROFIX_STR+fileName,workFilePath);
                FileUtils.copyFile(PROFIX_STR+fileName, versionFilePath);

                KtFileVersion oldKtFileVersion = versionService.selectKtFileVersionByVersion(ktFileRepositoryMsg.getEnableVersion());
                if (oldKtFileVersion == null) {
                    return AjaxResult.error("文件版本没有找到");
                }
                oldKtFileVersion.set_enable(BusiConstant.FILE_VERSION_ENABLE_NO);
                versionService.updateKtFileVersion(oldKtFileVersion);

                oldKtFileVersion.setId(null);
                oldKtFileVersion.set_enable(BusiConstant.FILE_VERSION_ENABLE_YES);
                oldKtFileVersion.setVersion(version);
                versionService.insertKtFileVersion(oldKtFileVersion);

                // 更新版本
                ktFileRepositoryMsg.setEnableVersion(version);
                ktFileRepositoryMsgService.updateKtFileRepositoryMsg(ktFileRepositoryMsg);

                KtFileRepository ktFileRepository = iKtFileRepositoryService.selectKtFileRepositoryById(fRepoId);
                FileRepositoryManager manager = new FileRepositoryManager(FILE_REPOSITORY_LOCATION, ktFileRepository.getDirectory(),
                        paraser);
                manager.parse();

            }
        }
        catch (Exception e)
        {
            logger.error("文件上传失败！", e);
            return error(e.getMessage());
        }

        return success();
    }

    @GetMapping("/switchVersion/{repoId}/{fileId}")
    public String addSwitchVersion(@PathVariable("repoId") Long repoId, @PathVariable("fileId") Long fileId, ModelMap mmap) {
        KtFileRepositoryMsg msg = ktFileRepositoryMsgService.selectKtFileRepositoryMsgById(fileId);
        mmap.addAttribute("fileMsg", msg);
        return prefix + "/switchVersion";
    }
}
